package com.woniuxy.user.config;


import com.woniuxy.user.exception.OAuthServerWebResponseExceptionTranslator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Arrays;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter{

	@Resource
	private BCryptPasswordEncoder passwordEncoder;

	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		//配置客户端
//		clients
//			.inMemory()		//内存方式
//			.withClient("client")	//客户端名字
//			.secret(passwordEncoder.encode("secret"))	//客户端秘钥
//			.authorizedGrantTypes("authorization_code","password","refresh_token")//授权类型
//			.scopes("all")	//授权范围
//			.redirectUris("http://www.woniuxy.com");	//回调网址，携带授权码
		clients.withClientDetails(clientDetailsService);
	}

	@Bean
	public ClientDetailsService clientDetailsService(DataSource dataSource) {
		//在数据库中去获取客户端信息（oauth_client_details表）
		return new JdbcClientDetailsService(dataSource);
	}

	// 认证管理器
	@Resource
	private AuthenticationManager authenticationManager;

	//配置使用的 AuthenticationManager 实现用户认证的功能
	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		endpoints
				.authenticationManager(authenticationManager) // 认证管理器
				.tokenServices(tokenServices())	// 配置token服务
				.exceptionTranslator(new OAuthServerWebResponseExceptionTranslator()); // 配置全局异常处理
	}

	@Resource
	private TokenStore tokenStore;

	@Resource
	private JwtAccessTokenConverter jwtAccessTokenConverter;

	@Resource
	private ClientDetailsService clientDetailsService;

	@Value("${oauth2.token_expire}")
	private int TOKEN_EXPIRE;

	@Value("${oauth2.refresh_token_expire}")
	private int REFRESH_TOKEN_EXPIRE;

	private AuthorizationServerTokenServices tokenServices(){
		// 创建服务对象
		DefaultTokenServices services = new DefaultTokenServices();
		// 设置客户端详情服务
		services.setClientDetailsService(clientDetailsService);
		// 支持刷新令牌
		services.setSupportRefreshToken(true);
		// 不重复使用refreshtoken，每次刷新之后只能用新的refreshtoken才能继续刷新
		services.setReuseRefreshToken(false);
		// 设置令牌存储策略
		services.setTokenStore(tokenStore);

		// 设置令牌增强
		TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
		tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter));
		services.setTokenEnhancer(tokenEnhancerChain);

		// 设置令牌过期时间
		services.setAccessTokenValiditySeconds(TOKEN_EXPIRE);
		services.setRefreshTokenValiditySeconds(REFRESH_TOKEN_EXPIRE);

		return services;
	}

	//设置 /oauth/check_token 端点，通过认证后可访问。
	//该端点对应 CheckTokenEndpoint类，用于校验访问令牌的有效性。
	//在客户端访问资源服务器时，会在请求中带上访问令牌。
	//在资源服务器收到客户端的请求时，会使用请求中的访问令牌，找授权服务器确认该访问令牌的有效性。
	@Override
	public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
		// 默认是denyAll()：拒绝所有
		oauthServer.checkTokenAccess("permitAll()");
	}
}